package com.erp.MyCamera;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import com.erp.Myapp;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

public class CameraPreview1 extends ViewGroup implements SurfaceHolder.Callback, Camera.AutoFocusCallback {

	private SurfaceView mSurfaceView;
	private SurfaceHolder mHolder;
	private Size mPreviewSize;
	private Size adapterSize;
	//private List<Size> mSupportedPreviewSizes;
	private Camera mCamera;
	private boolean isSupportAutoFocus = false;
	private Camera.Parameters parameters = null;
	private Context mContext;
	//private int mCurrentCameraId = 0;
	private int screenWidth;
	private int screenHeight;

	CameraPreview1(Context context, SurfaceView sv) {
		super(context);
		mContext = context;
		mSurfaceView = sv;
		mHolder = mSurfaceView.getHolder();
		mHolder.addCallback(this);
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		mHolder.setKeepScreenOn(true);
		isSupportAutoFocus = context.getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA_AUTOFOCUS);
		DisplayMetrics dm = new DisplayMetrics();
		((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
		screenWidth = dm.widthPixels;
		screenHeight = dm.heightPixels;
	}

	public void setCamera(Camera camera) {
		mCamera = camera;
		initCamera();
	}

	public void initCamera() {
		if (mCamera != null) {
			Camera.Parameters params = mCamera.getParameters();
			//mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
			requestLayout();
			if (mPreviewSize == null) {
				mPreviewSize = findBestPreviewResolution();
			}
			if (adapterSize == null) {
				adapterSize = findBestPictureResolution();
			}
			if (adapterSize != null) {
				params.setPictureSize(adapterSize.width, adapterSize.height);
			}
			if (mPreviewSize != null) {
				params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
			}
			params.setPictureFormat(PixelFormat.JPEG);
			List<String> focusModes = params.getSupportedFocusModes();
			if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
				// set the focus mode
				params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
				// set Camera parameters
				mCamera.setParameters(params);
			}
			if(!Myapp.sp.getBoolean("apd",false)) {
				setDispaly(params, mCamera);
			}
			//setCameraDisplayOrientation((Activity) mContext, mCurrentCameraId, mCamera);
			mCamera.setParameters(params);
		}
	}

	//控制图像的正确显示方向
	private void setDispaly(Camera.Parameters parameters, Camera camera) {
		if (Build.VERSION.SDK_INT >= 8) {
			setDisplayOrientation(camera, 90);
		} else {
			parameters.setRotation(90);
		}
	}

	//实现的图像的正确显示
	private void setDisplayOrientation(Camera camera, int i) {
		Method downPolymorphic;
		try {
			downPolymorphic = camera.getClass().getMethod("setDisplayOrientation",
					new Class[]{int.class});
			if (downPolymorphic != null) {
				downPolymorphic.invoke(camera, new Object[]{i});
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void setCameraDisplayOrientation(Activity activity,
			int cameraId, Camera camera) {
		Camera.CameraInfo info =
				new Camera.CameraInfo();
		Camera.getCameraInfo(cameraId, info);
		int rotation = activity.getWindowManager().getDefaultDisplay()
				.getRotation();
		int degrees = 0;
		switch (rotation) {
		case Surface.ROTATION_0:
			degrees = 0;
			break;
		case Surface.ROTATION_90:
			degrees = 90;
			break;
		case Surface.ROTATION_180:
			degrees = 180;
			break;
		case Surface.ROTATION_270:
			degrees = 270;
			break;
		}

		int result;
		if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
			result = (info.orientation + degrees) % 360;
			result = (360 - result) % 360;  // compensate the mirror
		} else {  // back-facing
			result = (info.orientation - degrees + 360) % 360;
		}
		camera.setDisplayOrientation(result);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
		final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
		setMeasuredDimension(width, height);
		//        if (mSupportedPreviewSizes != null) {
		//             mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
		//        }
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		if (changed && getChildCount() > 0) {
			final View child = getChildAt(0);

			final int width = r - l;
			final int height = b - t;

			int previewWidth = width;
			int previewHeight = height;
			if (mPreviewSize != null) {
				previewWidth = mPreviewSize.width;
				previewHeight = mPreviewSize.height;
			}

			// Center the child SurfaceView within the parent.
			if (width * previewHeight > height * previewWidth) {
				final int scaledChildWidth = previewWidth * height / previewHeight;
				child.layout((width - scaledChildWidth) / 2, 0,
						(width + scaledChildWidth) / 2, height);
			} else {
				final int scaledChildHeight = previewHeight * width / previewWidth;
				child.layout(0, (height - scaledChildHeight) / 2,
						width, (height + scaledChildHeight) / 2);
			}
		}
	}

	public void surfaceCreated(SurfaceHolder holder) {
		// The Surface has been created, acquire the camera and tell it where
		// to draw.
		try {
			if (mCamera != null) {
				mCamera.setPreviewDisplay(holder);
			}
		} catch (IOException e) {
			if (null != mCamera) {
				mCamera.release();
				mCamera = null;

			}
			e.printStackTrace();
		}
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
		if (holder.getSurface() == null) {
			return;
		}
		if (mCamera != null) {
			Camera.Parameters parameters = mCamera.getParameters();
			parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
			mCamera.setParameters(parameters);
			try {
				mCamera.setPreviewDisplay(holder);
			} catch (IOException e) {
				e.printStackTrace();
			}
			mCamera.startPreview();
			reAutoFocus();
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		// Surface will be destroyed when we return, so stop the preview.
		if (mCamera != null) {
			mCamera.stopPreview();
		}
	}

	/**
	 * 最小预览界面的分辨率
	 */
	private static final int MIN_PREVIEW_PIXELS = 480 * 320;
	/**
	 * 最大宽高比差
	 */
	private static final double MAX_ASPECT_DISTORTION = 0.15;

	/**
	 * 找出最适合的预览界面分辨率
	 *
	 * @return
	 */
	private Size findBestPreviewResolution() {
		Camera.Parameters cameraParameters = mCamera.getParameters();
		Size defaultPreviewResolution = cameraParameters.getPreviewSize();

		List<Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();
		if (rawSupportedSizes == null) {
			return defaultPreviewResolution;
		}

		// 按照分辨率从大到小排序
		List<Size> supportedPreviewResolutions = new ArrayList<Size>(rawSupportedSizes);
		Collections.sort(supportedPreviewResolutions, new Comparator<Size>() {
			@Override
			public int compare(Size a, Size b) {
				int aPixels = a.height * a.width;
				int bPixels = b.height * b.width;
				if (bPixels < aPixels) {
					return -1;
				}
				if (bPixels > aPixels) {
					return 1;
				}
				return 0;
			}
		});

		StringBuilder previewResolutionSb = new StringBuilder();
		for (Size supportedPreviewResolution : supportedPreviewResolutions) {
			previewResolutionSb.append(supportedPreviewResolution.width).append('x').append(supportedPreviewResolution.height)
			.append(' ');
		}


		// 移除不符合条件的分辨率
		double screenAspectRatio = (double) screenWidth
		/ screenHeight;
		Iterator<Size> it = supportedPreviewResolutions.iterator();
		while (it.hasNext()) {
			Size supportedPreviewResolution = it.next();
			int width = supportedPreviewResolution.width;
			int height = supportedPreviewResolution.height;

			// 移除低于下限的分辨率，尽可能取高分辨率
			if (width * height < MIN_PREVIEW_PIXELS) {
				it.remove();
				continue;
			}

			// 在camera分辨率与屏幕分辨率宽高比不相等的情况下，找出差距最小的一组分辨率
			// 由于camera的分辨率是width>height，我们设置的portrait模式中，width<height
			// 因此这里要先交换然preview宽高比后在比较
			boolean isCandidatePortrait = width > height;
			int maybeFlippedWidth = isCandidatePortrait ? height : width;
			int maybeFlippedHeight = isCandidatePortrait ? width : height;
			double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
			double distortion = Math.abs(aspectRatio - screenAspectRatio);
			if (distortion > MAX_ASPECT_DISTORTION) {
				it.remove();
				continue;
			}

			// 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回
			if (maybeFlippedWidth == screenWidth
					&& maybeFlippedHeight == screenHeight) {
				return supportedPreviewResolution;
			}
		}


		// 如果没有找到合适的，并且还有候选的像素，则设置其中最大比例的，对于配置比较低的机器不太合适
		if (!supportedPreviewResolutions.isEmpty()) {
			Size largestPreview = supportedPreviewResolutions.get(0);
			return largestPreview;
		}


		// 没有找到合适的，就返回默认的

		return defaultPreviewResolution;
	}


	private Size findBestPictureResolution() {
		Camera.Parameters cameraParameters = mCamera.getParameters();
		List<Size> supportedPicResolutions = cameraParameters.getSupportedPictureSizes(); // 至少会返回一个值

		StringBuilder picResolutionSb = new StringBuilder();
		for (Size supportedPicResolution : supportedPicResolutions) {
			picResolutionSb.append(supportedPicResolution.width).append('x')
					.append(supportedPicResolution.height).append(" ");
		}

		Size defaultPictureResolution = cameraParameters.getPictureSize();

		// 排序
		List<Size> sortedSupportedPicResolutions = new ArrayList<Size>(
				supportedPicResolutions);
		Collections.sort(sortedSupportedPicResolutions, new Comparator<Size>() {
			@Override
			public int compare(Size a, Size b) {
				int aPixels = a.height * a.width;
				int bPixels = b.height * b.width;
				if (bPixels < aPixels) {
					return -1;
				}
				if (bPixels > aPixels) {
					return 1;
				}
				return 0;
			}
		});


		// 移除不符合条件的分辨率
		double screenAspectRatio = screenWidth
		/ (double) screenHeight;
		Iterator<Size> it = sortedSupportedPicResolutions.iterator();
		while (it.hasNext()) {
			Size supportedPreviewResolution = it.next();
			int width = supportedPreviewResolution.width;
			int height = supportedPreviewResolution.height;

			// 在camera分辨率与屏幕分辨率宽高比不相等的情况下，找出差距最小的一组分辨率
			// 由于camera的分辨率是width>height，我们设置的portrait模式中，width<height
			// 因此这里要先交换然后在比较宽高比
			boolean isCandidatePortrait = width > height;
			int maybeFlippedWidth = isCandidatePortrait ? height : width;
			int maybeFlippedHeight = isCandidatePortrait ? width : height;
			double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
			double distortion = Math.abs(aspectRatio - screenAspectRatio);
			if (distortion > MAX_ASPECT_DISTORTION) {
				it.remove();
				continue;
			}
		}

		// 如果没有找到合适的，并且还有候选的像素，对于照片，则取其中最大比例的，而不是选择与屏幕分辨率相同的
		if (!sortedSupportedPicResolutions.isEmpty()) {
			return sortedSupportedPicResolutions.get(0);
		}

		// 没有找到合适的，就返回默认的
		return defaultPictureResolution;
	}

	private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
		final double ASPECT_TOLERANCE = 0.1;
		double targetRatio = (double) w / h;
		if (sizes == null)
			return null;

		Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;

		int targetHeight = h;

		// Try to find an size match aspect ratio and size
		for (Size size : sizes) {
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
				continue;
			if (Math.abs(size.height - targetHeight) < minDiff) {
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		}

		// Cannot find the one match the aspect ratio, ignore the requirement
		if (optimalSize == null) {
			minDiff = Double.MAX_VALUE;
			for (Size size : sizes) {
				if (Math.abs(size.height - targetHeight) < minDiff) {
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}


	public void reAutoFocus() {
		if (isSupportAutoFocus) {
			mCamera.autoFocus(new Camera.AutoFocusCallback() {
				@Override
				public void onAutoFocus(boolean success, Camera camera) {
				}
			});
		}
	}

	public List<Size> getResolutionList() {
		return mCamera.getParameters().getSupportedPreviewSizes();
	}

	public Size getResolution() {
		Camera.Parameters params = mCamera.getParameters();
		Size s = params.getPreviewSize();
		return s;
	}

	/*public void setCurrentCameraId(int current) {
		mCurrentCameraId = current;
	}*/

	//定点对焦的代码
	public void pointFocus(PointF pointF) {
		mCamera.cancelAutoFocus();
		parameters = mCamera.getParameters();
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
			//showPoint(x, y);
			focusOnTouch(pointF);
		}
		mCamera.setParameters(parameters);
		autoFocus();
	}

	//实现自动对焦
	public void autoFocus() {
		new Thread() {
			@Override
			public void run() {
				try {
					sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (mCamera == null) {
					return;
				}
				mCamera.autoFocus(new Camera.AutoFocusCallback() {
					@Override
					public void onAutoFocus(boolean success, Camera camera) {
						if (success) {
							initCamera();//实现相机的参数初始化
						}
					}
				});
			}
		};
	}

	@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
	private void showPoint(int x, int y) {
		if (parameters.getMaxNumMeteringAreas() > 0) {
			List<Camera.Area> areas = new ArrayList<Camera.Area>();
			WindowManager wm = (WindowManager) getContext()
					.getSystemService(Context.WINDOW_SERVICE);
			//xy变换了
			int rectY = -x * 2000 / wm.getDefaultDisplay().getWidth() + 1000;
			int rectX = y * 2000 / wm.getDefaultDisplay().getHeight() - 1000;
			int left = rectX < -900 ? -1000 : rectX - 100;
			int top = rectY < -900 ? -1000 : rectY - 100;
			int right = rectX > 900 ? 1000 : rectX + 100;
			int bottom = rectY > 900 ? 1000 : rectY + 100;
			Rect area1 = new Rect(left, top, right, bottom);
			areas.add(new Camera.Area(area1, 800));
			parameters.setMeteringAreas(areas);
		}

		parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
	}

	@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
	public void focusOnTouch(PointF event) {
		Rect focusRect = calculateTapArea(event.x, event.y, 1f);
		Rect meteringRect = calculateTapArea(event.x, event.y, 1.5f);

		Camera.Parameters parameters = mCamera.getParameters();
		parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

		if (parameters.getMaxNumFocusAreas() > 0) {
			List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
			focusAreas.add(new Camera.Area(focusRect, 1000));

			parameters.setFocusAreas(focusAreas);
		}

		if (parameters.getMaxNumMeteringAreas() > 0) {
			List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
			meteringAreas.add(new Camera.Area(meteringRect, 1000));

			parameters.setMeteringAreas(meteringAreas);
		}
		mCamera.setParameters(parameters);
		mCamera.autoFocus(this);
	}

	/**
	 * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
	 */
	private Rect calculateTapArea(float x, float y, float coefficient) {
		float focusAreaSize = 300;
		int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();

		int centerX = (int) (x / getResolution().width * 2000 - 1000);
		int centerY = (int) (y / getResolution().height * 2000 - 1000);

		int left = clamp(centerX - areaSize / 2, -1000, 1000);
		int right = clamp(left + areaSize, -1000, 1000);
		int top = clamp(centerY - areaSize / 2, -1000, 1000);
		int bottom = clamp(top + areaSize, -1000, 1000);

		return new Rect(left, top, right, bottom);
	}

	private int clamp(int x, int min, int max) {
		if (x > max) {
			return max;
		}
		if (x < min) {
			return min;
		}
		return x;
	}

	@Override
	public void onAutoFocus(boolean success, Camera camera) {

	}

	public void setNull() {
		adapterSize = null;
		mPreviewSize = null;
	}

}
